using System;
using System.Collections.Generic;
using NAsserter.Impl;

namespace NAsserter
{
    /// <summary>
    /// Performs assertions and throws exceptions if the assertions prove to be false.
    /// </summary>
    public static class AssertThat
    {
        /// <summary>
        /// Perform an assertion on an argument.
        /// </summary>
        /// <typeparam name="T">The type of the argument.</typeparam>
        /// <param name="obj">The object or value of the argument.</param>
        /// <param name="name">The name of the argument.</param>
        /// <returns></returns>
        public static IArgumentExpressions<T> Argument<T>(T obj, string name)
        {
            return new ArgumentExpressionsImpl<T>(obj, name);
        }

        internal static bool IsValid<T>(T obj)
        {
            var type = typeof (T);
            
            return 
                // a value type may be Nullable<> or not check. Non-Nullable<> value types are always valid because their value cannot be null
                (type.IsValueType && (!type.IsGenericType || !(type.GetGenericTypeDefinition() == typeof(Nullable<>)))) 
                
                // non ValueType or reference type with a null is not valid
                || obj != null;
        }

        internal static int Compare<T>(T obj, T compareTo)
        {
            if (obj is IComparable)
            {
                return (((IComparable) obj).CompareTo(compareTo));
            }
            else if (obj is IComparable<T>)
            {
                return (((IComparable<T>)obj).CompareTo(compareTo));
            }

            throw new ArgumentException("Expected target object type to implement IComparable or IComparable<T>", "obj");
        }

        internal static string ToString<T>(IEnumerable<T> enumerable)
        {
            var stringList = new List<string>();

            foreach (var o in enumerable)
            {
                stringList.Add(o.ToString());
            }

            return string.Join(", ", stringList.ToArray());
        }
    }

}